﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Microsoft.Practices.EnterpriseLibrary.Common.Configuration;
using System.Configuration;

namespace Thallo.Configuration {
    public partial class ThalloSection {
        public const string SECTION_NAME = "thallo";
        
        static Lazy<ThalloSection> __value = new Lazy<ThalloSection>(() => {
            return LoadConfig("thallo.config");
        });

        static ThalloSection LoadConfig(string fileName) {
            var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fileName);
            if (!File.Exists(file))
                throw new FileNotFoundException(file);
            var cfg = new Microsoft.Practices.EnterpriseLibrary.Common.Configuration.FileConfigurationSource(file);
            var section = cfg.GetSection(SECTION_NAME) as ThalloSection;
            foreach (FileElement item in section.Include) {
                var asms = GetConfigFilesAssemblySectionInfo(item);
                foreach (var asm in asms) {
                    if (section.Assemblies.Cast<AssemblyElement>().Any(c => c.Name == asm.Name))
                        throw new ArgumentException(asm.Name + " has been exist.");
                    section.Assemblies.Add(asm);
                }
            }
            return MergeSection(section);
        }

        static ThalloSection MergeSection(ThalloSection root) {
            if (root.Include.Count == 0)
                return root;
            foreach (FileElement item in root.Include) {
                var section = LoadConfig(item.Name);
                foreach (ConfigurationProperty prop in section.Properties) {
                    if (prop.Type.BaseType != typeof(ConfigurationElementCollection))
                        continue;
                    var desc = root[prop.Name] as ConfigurationElementCollection;
                    var mi = desc.GetType().GetMethod("Add", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public);
                    var source = root[prop] as ConfigurationElementCollection;
                    foreach (var element in source.Cast<ConfigurationElement>()) {
                        mi.Invoke(desc, new object[] { element });
                    }
                }
            }
            return root;
        }


        static IEnumerable<AssemblyElement> GetConfigFilesAssemblySectionInfo(FileElement fe) {
            if (string.IsNullOrWhiteSpace(fe.Name))
                return null;
            var file = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, fe.Name);
            if (!File.Exists(file))
                throw new FileNotFoundException(file);

            using (var cfg = new FileConfigurationSource(file)) {
                var section = cfg.GetSection(SECTION_NAME) as ThalloSection;
                var items = section.Assemblies.Cast<AssemblyElement>();
                return items;
            }
        }

        public static ThalloSection Current { get { return __value.Value; } }

    }

    class DependencyElementComparer : IEqualityComparer<DependencyElement> {

        public bool Equals(DependencyElement x, DependencyElement y) {
            return string.Compare(x.Type, y.Type, false) == 0 && string.Compare(x.Method,y.Method,false) == 0;
        }

        public int GetHashCode(DependencyElement obj) {
            return obj.Name.GetHashCode();
        }
    }
}
